home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / mush6.0 / part14 < prev    next >
Encoding:
Internet Message Format  |  1988-04-12  |  45.8 KB

  1. From: island!argv@sun.com (Dan Heller)
  2. Subject: Mail User's Shell, version 6.0
  3.  
  4. #! /bin/sh
  5. # This is a shell archive.  Remove anything before this line, then unpack
  6. # it by saving it into a file and typing "sh file".  To overwrite existing
  7. # files, type "sh file -c".  You can also feed this as standard input via
  8. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  9. # will see the following message at the end:
  10. #        "End of archive 14 (of 14)."
  11. # Contents:  mail.c
  12. # Wrapped by rsalz@fig.bbn.com on Wed Apr 13 20:04:57 1988
  13. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  14. if test -f 'mail.c' -a "${1}" != "-c" ; then 
  15.   echo shar: Will not clobber existing file \"'mail.c'\"
  16. else
  17. echo shar: Extracting \"'mail.c'\" \(44050 characters\)
  18. sed "s/^X//" >'mail.c' <<'END_OF_FILE'
  19. X/* @(#)mail.c     (c) copyright 1986 (Dan Heller) */
  20. X
  21. X#include "mush.h"
  22. X
  23. X/*
  24. X * mail.c --
  25. X *    do_mail()     invoked from within mail.  see function for description.
  26. X *    abort_mail()    suntools specific: resets panel items and so forth.
  27. X *    start_file()      creates the editing file and reset signal catching.
  28. X *    mail_someone()    called from do_mail() or from the shell.
  29. X *    add_to_letter()    adds the next line to letter --determine ~ escapes.
  30. X *    finish_up_letter()  prompts for Cc:, verifies user really wants to send
  31. X *    send_it()        invokes mailer, sends to record file, adds signature,
  32. X *            fortune, expands aliases, adds own_hdrs.
  33. X *    rm_edfile()    signals are directed here. remove letter, longjmp
  34. X *
  35. X * The flow of control in this file is NOT obvious to allow for both text
  36. X * and suntools _event driven_ attributes.  In text, the flow is far more
  37. X * obvious because it is sequential. In suntools, each function is called
  38. X * from outside this modual.  Keystrokes are interpreted individually and
  39. X * queued up in "rite.c".  select.c calls add_to_letter when a \n is entered
  40. X * passing the string stored in rite.c.  If you're trying to follow the flow
  41. X * of control for suntools, keep the event drivers in mind and follow select.c
  42. X * and rite.c
  43. X */
  44. X#define TO_FIELD    1
  45. X#define SUBJECT        2
  46. X#define CC_FIELD    3
  47. X#define BC_FIELD    4
  48. X
  49. static char Subject[BUFSIZ],To[BUFSIZ],Cc[BUFSIZ],Bcc[BUFSIZ],in_reply_to[256];
  50. static int killme;
  51. static u_long flags;
  52. static int (*oldterm)(), (*oldint)(), (*oldquit)();
  53. static void send_it();
  54. static jmp_buf cntrl_c_buf;
  55. FILE *ed_fp;
  56. char *edfile;
  57. X
  58. X/* argc, and argv could be null if coming from compose */
  59. do_mail(n, argv, list)
  60. register int n;   /* no need for "argc", so use the space for a variable */
  61. register char **argv, *list;
  62. X{
  63. X    char firstchar = (argv)? **argv: 'm';
  64. X    register char *to = NULL, *cc = NULL, *subj = NULL;
  65. X    u_long flgs = 0;
  66. X
  67. X    if (ison(glob_flags, IS_GETTING)) {
  68. X    print("You must finish the letter you are editing first.\n");
  69. X    return -1;
  70. X    }
  71. X    if (ison(glob_flags, DO_PIPE)) {
  72. X    print("You can't pipe through the mail command.\n");
  73. X    return -1;
  74. X    }
  75. X    turnon(flgs, NO_IGNORE); /* if we include a message, include all hdrs */
  76. X
  77. X    if (do_set(set_options, "autoedit"))
  78. X    turnon(flgs, EDIT);
  79. X#ifdef VERBOSE_ARG
  80. X    if (do_set(set_options, "verbose"))
  81. X    turnon(flgs, VERBOSE);
  82. X#endif /* VERBOSE_ARG */
  83. X    if (do_set(set_options, "autosign"))
  84. X    turnon(flgs, SIGN);
  85. X    /* If piped to mail, include the messages piped */
  86. X    if (ison(glob_flags, IS_PIPE))
  87. X    turnon(flgs, INCLUDE);
  88. X    else if (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))
  89. X    turnon(flgs, INCLUDE), set_msg_bit(list, current_msg);
  90. X    while (argv && *argv && *++argv && **argv == '-') {
  91. X    n = 1;
  92. X    while (n && argv[0][n])
  93. X        switch (argv[0][n]) {
  94. X#ifdef VERBOSE_ARG
  95. X        case 'v': turnon(flgs, VERBOSE); n++; break;
  96. X#endif /* VERBOSE_ARG */
  97. X        case 'e': turnon(flgs, EDIT); n++;
  98. X        when 'F': turnon(flgs, DO_FORTUNE); n++;
  99. X        when 's':
  100. X            if (argv[1])
  101. X            n = 0, subj = *++argv;
  102. X            else
  103. X            n++, turnon(flgs, NEW_SUBJECT);
  104. X        when 'i': case 'h': case 'f': {
  105. X            int m;
  106. X            if (!msg_cnt) {
  107. X            print("No message to include!\n");
  108. X            return -1;
  109. X            }
  110. X            if (argv[0][n] == 'i') {
  111. X            turnon(flgs, INCLUDE);
  112. X            turnoff(flgs, INCLUDE_H);
  113. X            turnoff(flgs, FORWARD);
  114. X            } else if (argv[0][n] == 'h') {
  115. X            turnon(flgs, INCLUDE_H);
  116. X            turnoff(flgs, INCLUDE);
  117. X            turnoff(flgs, FORWARD);
  118. X            } else if (argv[0][n] == 'f') {
  119. X            turnon(flgs, FORWARD);
  120. X            turnoff(flgs, INCLUDE_H);
  121. X            turnoff(flgs, INCLUDE);
  122. X            }
  123. X            /* "-i 3-5" or "-i3-5"  Consider the latter case first */
  124. X            if (!argv[0][++n])
  125. X            argv++, n = 0;
  126. X            (*argv) += n;
  127. X            m = get_msg_list(argv, list);
  128. X            (*argv) -= n;
  129. X            if (m == -1)
  130. X            return -1;
  131. X            /* if there were args, then go back to the first char
  132. X             * in the next argv
  133. X             */
  134. X            if (m)
  135. X            n = 0;
  136. X            if (!n) /* n may be 0 from above! */
  137. X            argv += (m-1);
  138. X        }
  139. X        otherwise:
  140. X            if (argv[0][n] != '?')
  141. X            wprint("%c: unknown option\n", argv[0][n]);
  142. X            wprint("available options\n");
  143. X#ifdef VERBOSE_ARG
  144. X            wprint("v      verbose (passed to mail delivery system)\n");
  145. X#endif /* VERBOSE_ARG */
  146. X            wprint("e      immediately enter editor (autoedit)\n");
  147. X            wprint("F      add fortune to the end of message.\n");
  148. X            wprint("s [subject]  prompt for or set subject.\n");
  149. X            wprint("i [msg#'s]   include msg_list into letter.\n");
  150. X            wprint("h [msg#'s]   include msg_list with headers.\n");
  151. X            wprint("f [msg#'s]   forward msg_list (not indented).\n");
  152. X            return -1;
  153. X        }
  154. X    }
  155. X    *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
  156. X    if (lower(firstchar) == 'r') {
  157. X    char *old_fmt = hdr_format;
  158. X    to = reply_to(current_msg, (firstchar == 'R'), To);
  159. X    if (firstchar == 'R')
  160. X        cc = cc_to(current_msg, Cc);
  161. X    if (do_set(set_options, "auto_route"))
  162. X        fix_addresses(To, Cc);
  163. X    if (hdr_format = do_set(set_options, "in_reply_to"))
  164. X        (void) strcpy(in_reply_to, compose_hdr(current_msg)+9); /* magic# */
  165. X    hdr_format = old_fmt;
  166. X    }
  167. X    if (ison(flgs, FORWARD) ||
  168. X        lower(firstchar) == 'r' && isoff(flgs, NEW_SUBJECT)) {
  169. X    char buf[sizeof(Subject)];
  170. X    if (ison(flgs, NEW_SUBJECT))
  171. X        print("Forwarded mail can't have subject changed.\n");
  172. X    turnoff(flgs, NEW_SUBJECT);
  173. X    if (subj = subject_to(current_msg, buf))
  174. X        subj = strcpy(Subject, buf + 4*(lower(firstchar) != 'r'));
  175. X    } else if (isoff(flgs, NEW_SUBJECT) && do_set(set_options, "ask"))
  176. X    turnon(flgs, NEW_SUBJECT);
  177. X    if (argv && *argv) {
  178. X    char buf[BUFSIZ];
  179. X    (void) argv_to_string(buf, argv);
  180. X    fix_up_addr(buf);
  181. X    to = &To[strlen(To)];
  182. X    if (*To)
  183. X        to += Strcpy(to-1, ", ") - 1;
  184. X    (void) strcpy(to, buf);
  185. X    to = To;
  186. X    }
  187. X    if (do_set(set_options, "fortune"))
  188. X    turnon(flgs, DO_FORTUNE);
  189. X#ifdef SUNTOOL
  190. X    if (istool) {
  191. X    do_clear();
  192. X    panel_set(abort_item,   PANEL_SHOW_ITEM, TRUE,  0);
  193. X    panel_set(comp_item,    PANEL_SHOW_ITEM, FALSE, 0);
  194. X    panel_set(read_item,    PANEL_SHOW_ITEM, FALSE, 0);
  195. X    panel_set(respond_item, PANEL_SHOW_ITEM, FALSE, 0);
  196. X    }
  197. X#endif /* SUNTOOL */
  198. X    return mail_someone(to, subj, cc, flgs, list);
  199. X}
  200. X
  201. X#ifdef SUNTOOL
  202. X/* panel item selection -- it's here because of local (static) variables */
  203. abort_mail(item, value)
  204. Panel_item item;
  205. X{
  206. X    get_hdr_field = 0;
  207. X    if (item == abort_item && value != 2) {
  208. X    print("Aborted letter.");
  209. X    killme = 1, rm_edfile(SIGINT);
  210. X    flags = 0;
  211. X    }
  212. X    panel_set(comp_item,    PANEL_SHOW_ITEM, TRUE,  0);
  213. X    panel_set(send_item,    PANEL_SHOW_ITEM, FALSE, 0);
  214. X    panel_set(edit_item,    PANEL_SHOW_ITEM, FALSE, 0);
  215. X    panel_set(abort_item,   PANEL_SHOW_ITEM, FALSE, 0);
  216. X    panel_set(read_item,    PANEL_SHOW_ITEM, TRUE,  0);
  217. X    panel_set(respond_item, PANEL_SHOW_ITEM, TRUE,  0);
  218. X    turnoff(glob_flags, IS_GETTING);
  219. X    unlock_cursors();
  220. X}
  221. X#endif /* SUNTOOL */
  222. X
  223. mail_someone(to, subject, cc, flgs, list)
  224. register char *to, *subject, *cc, *list;
  225. u_long flgs;
  226. X{
  227. X    register char *p;
  228. X
  229. X    flags = flgs;
  230. X#ifdef SUNTOOL
  231. X    if (istool)
  232. X    rite(_tty.sg_kill), do_clear();
  233. X#endif /* SUNTOOL */
  234. X    if (to && *to) {
  235. X    if (!*To)
  236. X        (void) strncpy(To, to, sizeof(To));
  237. X    if (istool)
  238. X        wprint("To: %s\n", To);
  239. X    } else
  240. X#ifdef SUNTOOL
  241. X    if (istool)
  242. X        turnon(get_hdr_field, TO_FIELD);
  243. X    else
  244. X#endif /* SUNTOOL */
  245. X        to = NO_STRING;
  246. X    if (subject && *subject) {
  247. X    if (!*Subject)
  248. X        (void) strncpy(Subject, subject, sizeof(Subject));
  249. X    if (istool)
  250. X        wprint("Subject: %s\n", Subject);
  251. X    } else
  252. X#ifdef SUNTOOL
  253. X    if (istool && !*Subject && ison(flags, NEW_SUBJECT))
  254. X        turnon(get_hdr_field, SUBJECT);
  255. X    else
  256. X#endif /* SUNTOOL */
  257. X        subject = NO_STRING;
  258. X    if (cc && *cc) {
  259. X    if (!*Cc)
  260. X        (void) strncpy(Cc, cc, sizeof(Cc));
  261. X    if (istool)
  262. X        wprint("Cc: %s\n", Cc);
  263. X    } else
  264. X#ifdef SUNTOOL  /* get_hdr_field -- prevents prompting on reply and forward */
  265. X    if (istool && get_hdr_field && do_set(set_options, "askcc"))
  266. X        turnon(get_hdr_field, CC_FIELD);
  267. X    else
  268. X#endif /* SUNTOOL */
  269. X        cc = NO_STRING;
  270. X
  271. X    if (ison(glob_flags, REDIRECT)) {
  272. X    send_it(); /* doesn't return */
  273. X    return 0;
  274. X    }
  275. X    /* if (!*to) then prompting will be done */
  276. X    if (!istool) {
  277. X    if (!(p = set_header("To: ", to, !*to)) || !*p) {
  278. X        puts("No recipients, can't mail.");
  279. X        return -1;
  280. X    }
  281. X    if (!*to) /* if user typed To-line here, fix up the address line */
  282. X        fix_up_addr(p);
  283. X    (void) strcpy(To, p);
  284. X    /* don't prompt for subject if forwarding mail */
  285. X    if (p = set_header("Subject: ", subject,
  286. X        !*subject && ison(flags, NEW_SUBJECT)))
  287. X        (void) strcpy(Subject, p);
  288. X    if (*Cc)
  289. X        printf("Cc: %s\n", Cc);
  290. X    putchar('\n');
  291. X    }
  292. X#ifdef SUNTOOL
  293. X    else if (!get_hdr_field) {
  294. X    panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  295. X    panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  296. X    }
  297. X#endif /* SUNTOOL */
  298. X    return start_file(list);
  299. X}
  300. X
  301. start_file(list)
  302. char *list;
  303. X{
  304. X    register char  *home;
  305. X    register int   i;
  306. X    char         line[MAXPATHLEN];
  307. X
  308. X    if (!(home = do_set(set_options, "home")) || !*home)
  309. alted:
  310. X    home = ALTERNATE_HOME;
  311. X    (void) mktemp(sprintf(line, "%s/%s", home, EDFILE));
  312. X    strdup(edfile, line);
  313. X    {
  314. X    int omask = umask(077);
  315. X    ed_fp = fopen(edfile, "w+");
  316. X    (void) umask(omask);
  317. X    if (!ed_fp) {
  318. X        if (home != ALTERNATE_HOME)
  319. X        goto alted;
  320. X#ifdef SUNTOOL
  321. X        if (istool)
  322. X        abort_mail(NO_ITEM, 0);
  323. X#endif /* SUNTOOL */
  324. X        error("can't create %s", edfile);
  325. X        return -1;
  326. X    }
  327. X    }
  328. X    if (!istool) {
  329. X    oldint = signal(SIGINT, rm_edfile);
  330. X    oldquit = signal(SIGQUIT, rm_edfile);
  331. X    oldterm = signal(SIGTERM, rm_edfile);
  332. X    }
  333. X
  334. X    /* if flags call for it, include current message (with header?) */
  335. X    if (ison(flags, INCLUDE) || ison(flags,FORWARD) || ison(flags,INCLUDE_H)) {
  336. X    long copy_flgs = 0, is_forw = ison(flags, FORWARD);
  337. X    char buf[sizeof(To)];
  338. X    if (!is_forw)
  339. X        turnon(copy_flgs, INDENT);
  340. X    if (ison(flags, INCLUDE))
  341. X        turnon(copy_flgs, NO_HEADER);
  342. X    if (ison(flags, INCLUDE) || ison(flags, FORWARD))
  343. X        turnon(copy_flgs, NO_IGNORE);
  344. X#ifdef SUNTOOL
  345. X    if (istool)
  346. X        lock_cursors();
  347. X#endif /* SUNTOOL */
  348. X    for (i = 0; i < msg_cnt; i++)
  349. X        if (msg_bit(list, i)) {
  350. X        if (is_forw && ison(flags, EDIT)) {
  351. X            (void) reply_to(i, FALSE, buf);
  352. X            fprintf(ed_fp, "--- Forwarded mail from %s\n\n", buf);
  353. X        }
  354. X        wprint("%sing message %d ...",
  355. X            is_forw? "forward" : "includ", i+1);
  356. X        wprint("(%d lines)\n", copy_msg(i, ed_fp, copy_flgs));
  357. X        set_isread(i); /* if we included it, we read it, right? */
  358. X        if (is_forw && ison(flags, EDIT))
  359. X            fprintf(ed_fp,
  360. X            "\n--- End of forwarded message from %s\n", buf);
  361. X        }
  362. X    fflush(ed_fp);
  363. X#ifdef SUNTOOL
  364. X    if (istool)
  365. X        unlock_cursors();
  366. X#endif /* SUNTOOL */
  367. X    }
  368. X    if (ison(glob_flags, WARNING)) {
  369. X    if (escape && *escape != DEF_ESCAPE[0])
  370. X        wprint("(escape character is set to `%c')\n", *escape);
  371. X    }
  372. X    turnon(glob_flags, IS_GETTING);
  373. X    /* enter editor if autoedit and not toolmode */
  374. X    if (
  375. X#ifdef SUNTOOL
  376. X        (!istool || !get_hdr_field) &&
  377. X#endif /* SUNTOOL */
  378. X    /* do an "if" again in case editor not found and EDIT turned off */
  379. X                    ison(flags, EDIT)) {
  380. X    char *argv[3];
  381. X    if (!(argv[0] = do_set(set_options, "visual")) || !*argv[0])
  382. X        argv[0] = DEF_EDITOR;
  383. X    argv[1] = edfile;
  384. X    argv[2] = NULL;
  385. X    print("Starting \"%s\"...\n", argv[0]);
  386. X    fclose(ed_fp);
  387. X    ed_fp = NULL_FILE;
  388. X    execute(argv);
  389. X    turnoff(flags, EDIT);
  390. X    turnoff(flags, FORWARD); /* forwarded messages must be unedited */
  391. X    /* upon exit of editor, user must now type ^D or "." to send */
  392. X    if (istool)
  393. X        return 0;
  394. X    if (!(ed_fp = fopen(edfile, "r+"))) {
  395. X        error("can't reopen %s", edfile);
  396. X        return -1;
  397. X    }
  398. X    (void) fseek(ed_fp, 0L, 2);
  399. X    puts("continue editing letter or ^D to send");
  400. X    } else if (ison(flags, FORWARD) &&
  401. X#ifdef SUNTOOL
  402. X           (!istool || !get_hdr_field) &&
  403. X#endif /* SUNTOOL */
  404. X           finish_up_letter())
  405. X    return 0; /* if forwarding mail, check to see if tool requires To: */
  406. X#ifdef SUNTOOL
  407. X    if (istool) {
  408. X    /* If toolmode, we're ready for IO. Give first prompt if not given */
  409. X    if (ison(get_hdr_field, TO_FIELD))
  410. X        wprint("To: ");
  411. X    else if (ison(get_hdr_field, SUBJECT))
  412. X        wprint("Subject: ");
  413. X    else if (ison(get_hdr_field, CC_FIELD))
  414. X        wprint("Cc: ");
  415. X    type_cursor(PIX_SRC);
  416. X    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  417. X    return 0;
  418. X    }
  419. X#endif /* SUNTOOL */
  420. X    i = 0;
  421. X    do  {
  422. X    /* If the user hits ^C in cbreak mode, mush will return to
  423. X     * Getstr and not clear the buffer. whatever is typed next will
  424. X     * be appended to the line.  jumping here will force the line to
  425. X     * be cleared cuz it's a new call.
  426. X     */
  427. X    (void) setjmp(cntrl_c_buf);
  428. X    while (Getstr(line, sizeof(line), 0) > -1)
  429. X        if ((i = add_to_letter(line)) <= 0)
  430. X        break;
  431. X    } while (i >= 0 && !finish_up_letter());
  432. X    return i; /* return -1 if ~x or ~q to terminate letter */
  433. X}
  434. X
  435. char *tilde_commands[] = {
  436. X    "commands: [OPTIONAL argument]",
  437. X    "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
  438. X    "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
  439. X    "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
  440. X    "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
  441. X    "H [msg#'s]\tSame, but include the message headers from included messages",
  442. X    "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
  443. X    "t [list]\tChange list of recipients",
  444. X    "s [subject]\tModify [set] subject header",
  445. X    "c [cc list]\tModify [set] carbon copy recipients",
  446. X    "b [bcc list]\tModify [set] blind carbon recipients",
  447. X    "h\t\tModify all message headers",
  448. X    "S[!]\t\tInclude Signature file [suppress file]",
  449. X    "F[!]\t\tAdd a fortune at end of letter [don't add]",
  450. X    "w file\t\tWrite msg buffer to file name",
  451. X    "a file\t\tAppend msg buffer to file name",
  452. X    "r file\t\tRead filename into message buffer",
  453. X    "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
  454. X    "x \t\tQuit message; don't save in dead.letter.",
  455. X    "$variable\tInsert the string value for \"variable\" into message.",
  456. X    ":cmd\t\tRun the mail command \"cmd\".",
  457. X    "u\t\tedit previous line in file.",
  458. X    "E[!]\t\tClear contents of letter after saving to dead.letter [unless !].",
  459. X    0
  460. X};
  461. X
  462. X/*
  463. X * Add the line (char *) parameter to the letter.  Determine tilde
  464. X * escapes and determine what to do.  This function returns 0 to
  465. X * indicate user wants to end the letter, -1 if the letter cannot
  466. X * be sent (~q, ~x no buffer after editor, etc...) or 1 to indicate
  467. X * successful addition of the line to the letter.
  468. X */
  469. add_to_letter(line)
  470. register char *line;
  471. X{
  472. X    register char *p;
  473. X    char buf[BUFSIZ];
  474. X
  475. X    killme = 0;
  476. X    (void) fseek(ed_fp, 0L, 2);
  477. X#ifdef SUNTOOL
  478. X    if (get_hdr_field) {
  479. X    /* These are received in order by design! */
  480. X    if (ison(get_hdr_field, TO_FIELD)) {
  481. X        if (!*line) {
  482. X            wprint("There must be a recipient!\nTo: ");
  483. X        return 1;
  484. X        }
  485. X        fix_up_addr(line);
  486. X        (void) strcpy(To, line), turnoff(get_hdr_field, TO_FIELD);
  487. X    } else if (ison(get_hdr_field, SUBJECT)) {
  488. X        (void) strcpy(Subject, line);
  489. X        turnoff(get_hdr_field, SUBJECT);
  490. X    } else if (ison(get_hdr_field, CC_FIELD)) {
  491. X        fix_up_addr(line);
  492. X        (void) strcpy(Cc, line);
  493. X        turnoff(get_hdr_field, CC_FIELD);
  494. X    } else if (ison(get_hdr_field, BC_FIELD)) {
  495. X        fix_up_addr(line);
  496. X        (void) strcpy(Bcc, line);
  497. X        turnoff(get_hdr_field, BC_FIELD);
  498. X    }
  499. X
  500. X        if (ison(get_hdr_field, SUBJECT))
  501. X        (void) set_header("Subject: ", Subject, 1);
  502. X        else if (ison(get_hdr_field, CC_FIELD))
  503. X        (void) set_header("Cc: ", Cc, 1);
  504. X        else if (ison(get_hdr_field, BC_FIELD))
  505. X        (void) set_header("Bcc: ", Bcc, 1);
  506. X    panel_set(send_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  507. X    panel_set(edit_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  508. X    if (!get_hdr_field) {
  509. X        wprint("\n");
  510. X        if (ison(flags, EDIT)) {
  511. X        (void) add_to_letter(sprintf(line, "%cv", *escape));
  512. X        turnoff(flags, EDIT);
  513. X        }
  514. X    }
  515. X    return 1;
  516. X    }
  517. X#endif /* SUNTOOL */
  518. X    if (!strcmp(line, ".") && (istool || do_set(set_options, "dot")))
  519. X    return 0;
  520. X    if (*line != *escape) {
  521. X    fputs(line, ed_fp), fputc('\n', ed_fp), fflush(ed_fp);
  522. X    return 1;
  523. X    }
  524. X    /* all commands are "~c" (where 'c' is the command). set p = first
  525. X     * character after 'c' and skip whitespace
  526. X     */
  527. X    p = line+2;
  528. X    skipspaces(0);
  529. X    switch (line[1]) {
  530. X    case 'v' : case 'p': case 'e': {
  531. X        if (!*p || *p == 'i' && !p[1])
  532. X        switch (line[1]) {
  533. X            case 'p' :
  534. X            if (!(p = do_set(set_options, "pager")))
  535. X                p = DEF_PAGER;
  536. X            if (!*p || !strcmp(p, "internal"))
  537. X                p = NULL;
  538. X            when 'v' :
  539. X            if (p = do_set(set_options, "visual"))
  540. X                break;
  541. X            default :
  542. X            if (!(p = do_set(set_options, "editor")) || !*p)
  543. X                p = DEF_EDITOR;
  544. X        }
  545. X        if (line[1] == 'p') {
  546. X        rewind(ed_fp);
  547. X        (void) do_pager(p, TRUE); /* start the pager "p" */
  548. X        do_pager(sprintf(buf, "To: %s\n", To), FALSE);
  549. X        if (Subject[0])
  550. X            do_pager(sprintf(buf, "Subject: %s\n", Subject), FALSE);
  551. X        if (Cc[0])
  552. X            do_pager(sprintf(buf, "Cc: %s\n", Cc), FALSE);
  553. X        if (Bcc[0])
  554. X            do_pager(sprintf(buf, "Bcc: %s\n", Bcc), FALSE);
  555. X        do_pager(strcpy(buf, "--------\nMessage contains:\n"), FALSE);
  556. X        while (fgets(buf, sizeof(buf), ed_fp))
  557. X            if (do_pager(buf, FALSE) == EOF)
  558. X            break;
  559. X        (void) do_pager(NULL, FALSE); /* end pager */
  560. X        } else {
  561. X        char *argv[3];
  562. X        argv[0] = p;
  563. X        argv[1] = edfile;
  564. X        argv[2] = NULL;
  565. X        fclose(ed_fp);
  566. X        ed_fp = NULL_FILE;
  567. X        execute(argv); /* tool will return even tho editor isn't done */
  568. X        if (istool)
  569. X            return 1;
  570. X        if (!(ed_fp = fopen(edfile, "r+"))) {
  571. X            error("can't reopen %s", edfile);
  572. X            return -1;
  573. X        }
  574. X        }
  575. X    }
  576. X    when '$': {
  577. X        register char *p2;
  578. X        if (!(p2 = do_set(set_options, p)))
  579. X        wprint("(%s isn't set)\n", p);
  580. X        else
  581. X        fprintf(ed_fp, "%s\n", p2);
  582. X    }
  583. X    when ':': {
  584. X        char new[MAXMSGS_BITS];
  585. X        u_long save_flags = glob_flags;
  586. X
  587. X        turnon(glob_flags, IGN_SIGS);
  588. X        turnon(glob_flags, IGN_BANG);
  589. X        turnoff(glob_flags, DO_PIPE);
  590. X        turnoff(glob_flags, IS_PIPE);
  591. X        (void) cmd_line(p, new);
  592. X        glob_flags = save_flags;
  593. X#ifdef SUNTOOL
  594. X        if (istool && msg_pix) /* the command was to read a message */
  595. X        return 1;
  596. X#endif /* SUNTOOL */
  597. X    }
  598. X    when 'i': case 'f': case 'H': case 'm': {
  599. X        int  n;
  600. X        long copy_flgs = 0;
  601. X        char list[MAXMSGS_BITS];
  602. X
  603. X        if (!msg_cnt) {
  604. X        print("No messages.\n");
  605. X        break;
  606. X        }
  607. X        clear_msg_list(list);
  608. X        if (line[1] != 'f')
  609. X        turnon(copy_flgs, INDENT);
  610. X        if (line[1] == 'i')
  611. X        turnon(copy_flgs, NO_HEADER);
  612. X        if (!*p)
  613. X        set_msg_bit(list, current_msg);
  614. X        else if (!do_range(p, list))
  615. X        return 1;
  616. X#ifdef SUNTOOL
  617. X        if (istool)
  618. X        lock_cursors();
  619. X#endif /* SUNTOOL */
  620. X        for (n = 0; n < msg_cnt; n++)
  621. X        if (msg_bit(list, n)) {
  622. X            if (line[1] == 'f') {
  623. X            (void) reply_to(n, FALSE, buf);
  624. X            fprintf(ed_fp, "--- Forwarded mail from %s\n\n", buf);
  625. X            }
  626. X            wprint("Including message %d ... ", n+1);
  627. X            wprint("(%d lines)\n", copy_msg(n, ed_fp, copy_flgs));
  628. X            set_isread(n);
  629. X            if (line[1] == 'f')
  630. X        fprintf(ed_fp,"\n--- End of forwarded message from %s\n\n",buf);
  631. X        }
  632. X#ifdef SUNTOOL
  633. X        if (istool)
  634. X        unlock_cursors();
  635. X#endif /* SUNTOOL */
  636. X    }
  637. X    when 't':
  638. X#ifdef SUNTOOL
  639. X        if (!*p && istool) {
  640. X        turnon(get_hdr_field, TO_FIELD);
  641. X        (void) set_header("To: ", To, 1);
  642. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  643. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  644. X        return 1;
  645. X        }
  646. X#endif /* SUNTOOL */
  647. X        /* ~t address   is a special case ... append to address */
  648. X        if (*p) {
  649. X        fix_up_addr(p);
  650. X        (void) sprintf(To+strlen(To), ", %s", p);
  651. X        } else if (p = set_header("To: ", To, 1))
  652. X        if (!*p) {
  653. X            wprint("There must be a recipient!\n");
  654. X#ifdef SUNTOOL
  655. X            turnoff(get_hdr_field, TO_FIELD);
  656. X            panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  657. X            panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  658. X#endif /* SUNTOOL */
  659. X        } else {
  660. X            fix_up_addr(p);
  661. X            (void) strcpy(To, p);
  662. X        }
  663. X    when 's':
  664. X#ifdef SUNTOOL
  665. X        if (!*p && istool) {
  666. X        turnon(get_hdr_field, SUBJECT);
  667. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  668. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  669. X        (void) set_header("Subject: ", Subject, 1);
  670. X        return 1;
  671. X        }
  672. X#endif /* SUNTOOL */
  673. X        if (*p || (p = set_header("Subject: ", Subject, 1)))
  674. X        if (!*p)
  675. X            Subject[0] = 0;
  676. X        else
  677. X            (void) strcpy(Subject, p);
  678. X    when 'c':
  679. X#ifdef SUNTOOL
  680. X        if (!*p && istool) {
  681. X        turnon(get_hdr_field, CC_FIELD);
  682. X        (void) set_header("Cc: ", Cc, 1);
  683. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  684. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  685. X        return 1;
  686. X        }
  687. X#endif /* SUNTOOL */
  688. X        if (*p || (p = set_header("Cc: ", Cc, 1)))
  689. X        if (!*p)
  690. X            Cc[0] = 0;
  691. X        else {
  692. X            fix_up_addr(p);
  693. X            (void) strcpy(Cc, p);
  694. X        }
  695. X    when 'b':
  696. X#ifdef SUNTOOL
  697. X        if (!*p && istool) {
  698. X        turnon(get_hdr_field, BC_FIELD);
  699. X        (void) set_header("Bcc: ", Bcc, 1);
  700. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  701. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  702. X        return 1;
  703. X        }
  704. X#endif /* SUNTOOL */
  705. X        if (*p || (p = set_header("Bcc: ", Bcc, 1)))
  706. X        if (!*p)
  707. X            Bcc[0] = 0;
  708. X        else {
  709. X            fix_up_addr(p);
  710. X            (void) strcpy(Bcc, p);
  711. X        }
  712. X    when 'h':
  713. X#ifdef SUNTOOL
  714. X        if (istool) {
  715. X        turnon(get_hdr_field, TO_FIELD);
  716. X        turnon(get_hdr_field, SUBJECT);
  717. X        turnon(get_hdr_field, CC_FIELD);
  718. X        turnon(get_hdr_field, BC_FIELD);
  719. X        (void) set_header("To: ", To, 1);
  720. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  721. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  722. X        return 1;
  723. X        }
  724. X#endif /* SUNTOOL */
  725. X        while ((p = set_header("To: ", To, 1)) && !*p)
  726. X        wprint("(There must be a recipient.)\n");
  727. X        (void) strcpy(To, p);
  728. X        if (p = set_header("Subject: ", Subject, 1))
  729. X        if (!*p)
  730. X            Subject[0] = 0;
  731. X        else
  732. X            (void) strcpy(Subject, p);
  733. X        if (p = set_header("Cc: ", Cc, 1))
  734. X        if (!*p)
  735. X            Cc[0] = 0;
  736. X        else {
  737. X            fix_up_addr(p);
  738. X            (void) strcpy(Cc, p);
  739. X        }
  740. X        if (p = set_header("Bcc: ", Bcc, 1))
  741. X        if (!*p)
  742. X            Bcc[0] = 0;
  743. X        else {
  744. X            fix_up_addr(p);
  745. X            (void) strcpy(Bcc, p);
  746. X        }
  747. X    when 'S':
  748. X        if (*p == '!')
  749. X        turnoff(flags, SIGN), wprint("not ");
  750. X        else
  751. X        turnon(flags, SIGN);
  752. X        wprint("adding signature file at end of message.\n");
  753. X    when 'F':
  754. X        if (*p == '!')
  755. X        turnoff(flags, DO_FORTUNE), wprint("not ");
  756. X        else
  757. X        turnon(flags, DO_FORTUNE);
  758. X        wprint("adding fortune at end of message.\n");
  759. X    when 'w': case 'a': case 'r':
  760. X        if (!*p) {
  761. X        wprint("(you must specify a filename)\n");
  762. X        return 1;
  763. X        }
  764. X        (void) fseek(ed_fp, 0L, 2); /* append */
  765. X        file_to_fp(p, ed_fp, (line[1] == 'r')? "r":
  766. X                  (line[1] == 'w')? "w": "a");
  767. X    /* go up one line in the message file and allow the user to edit it */
  768. X    when 'u': {
  769. X        long newpos, pos = ftell(ed_fp);
  770. X        char oldline[256];
  771. X        if (istool) {
  772. X        wprint("(Not available in tool mode.)\n");
  773. X        return 1;
  774. X        }
  775. X        if (pos <= 0L) { /* pos could be -1 if ftell() failed */
  776. X        wprint("(No previous line in file.)\n");
  777. X        return 1;
  778. X        }
  779. X        /* get the last 256 bytes written and read backwards from the
  780. X         * current place until '\n' is found. Start by moving past the
  781. X         * first \n which is at the end of the line we want to edit
  782. X         */
  783. X        newpos = max(0, pos - 256L);
  784. X        (void) fseek(ed_fp, newpos, L_SET);
  785. X        /* don't fgets -- it'll stop at a \n */
  786. X        (void) read(fileno(ed_fp), line, (int)(pos-newpos));
  787. X        pos--;
  788. X        /* the last char in line should be a \n cuz it was last input */
  789. X        if (line[(int)(pos-newpos)] != '\n')
  790. X        wprint("I don't know how, but your last line ended with %c.\n",
  791. X            line[(int)(pos-newpos)]);
  792. X        else
  793. X        line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
  794. X        for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
  795. X        ;
  796. X        /* we've gone back to the end of the second previous line. Check
  797. X         * to see if the char we're pointing to is a \n.  It should be, but
  798. X         * if it's not, we moved back to the first line of the file.
  799. X         */
  800. X        if (line[(int)(pos-newpos)] == '\n')
  801. X        ++pos;
  802. X        /* save the old line that's there in case the user boo-boo's */
  803. X        (void) strcpy(oldline, line+(int)(pos-newpos));
  804. X        /* let set header print out the line and get the input */
  805. X        if (!(p = set_header("", line+(int)(pos-newpos), TRUE))) {
  806. X        wprint("Something bad happened and I don't know what it is.\n");
  807. X        p = oldline;
  808. X        } else if (*p == *escape && *++p != *escape) {
  809. X        wprint("(No %c escapes on %cu lines. Line unchanged.)\n",
  810. X                *escape, *escape);
  811. X        p = oldline;
  812. X        }
  813. X        /* seek to to the position where the new line will go */
  814. X        (void) fseek(ed_fp, pos, L_SET);
  815. X        /* put the newly typed line */
  816. X        (void) fputs(p, ed_fp); /* don't add \n. padding may be necessary */
  817. X        /* if the new line is less than the old line, we're going to do
  818. X         * one of two things.  The best thing to do is to truncate the
  819. X         * file to the end of the new line.  Sys-v can't do that, so we
  820. X         * pad the line with blanks.  May be messy in some cases, but...
  821. X         */
  822. X        if ((pos = strlen(p) - strlen(oldline)) < 0) {
  823. X#ifndef SYSV
  824. X        /* add the \n, flush the file, truncate to the current pos */
  825. X        fputc('\n', ed_fp), fflush(ed_fp);
  826. X        (void) ftruncate(fileno(ed_fp), (int)ftell(ed_fp));
  827. X#else
  828. X        /* pad with blanks to the length of the old line. add \n */
  829. X        while (pos++ < 0)
  830. X            fputc(' ', ed_fp);
  831. X        fputc('\n', ed_fp), fflush(ed_fp);
  832. X#endif /* SYSV */
  833. X        } else
  834. X        /* the new line is >= the old line, add \n -- no trunc req. */
  835. X            fputc('\n', ed_fp);
  836. X        return 1;
  837. X     }
  838. X    /* break;  not here cuz of "return" (lint). */
  839. X    case 'E':
  840. X        if (*p != '!' && !do_set(set_options, "nosave"))
  841. X        dead_letter();
  842. X        if (emptyfile(&ed_fp, edfile) == -1)
  843. X        error(edfile);
  844. X        else
  845. X        wprint("Message buffer empty\n");
  846. X    when 'q':
  847. X        /* save in dead.letter if nosave not set -- rm_edfile(-2). */
  848. X        rm_edfile(-2); /* doesn't return out of tool mode */
  849. X        return -1;
  850. X        /* break; not stated cuz of "return" (lint) */
  851. X    case 'x':
  852. X        /* don't save dead.letter -- simulate normal rm_edfile() call */
  853. X        rm_edfile(0);
  854. X#ifdef SUNTOOL
  855. X        if (istool) {
  856. X        wprint("*Letter aborted*");
  857. X        type_cursor(PIX_CLR);
  858. X        }
  859. X#endif /* SUNTOOL */
  860. X        return -1;
  861. X        /* break; (not specified for lint) */
  862. X    default:
  863. X        if (line[1] == *escape) {
  864. X        fputs(line+1, ed_fp), fputc('\n', ed_fp), fflush(ed_fp);
  865. X        return 1;
  866. X        } else if (line[1] == '?') {
  867. X        register int x;
  868. X        for (x = 0; tilde_commands[x]; x++)
  869. X            wprint("%s%s\n", escape, tilde_commands[x]);
  870. X        wprint("%s%s\t\tbegin a line with a single %s\n",
  871. X            escape, escape, escape);
  872. X#ifdef SUNTOOL
  873. X        if (istool)
  874. X            (void) help(0, "compose", tool_help);
  875. X#endif /* SUNTOOL */
  876. X        } else
  877. X        wprint("`%c': unknown %c escape. Use %c? for help.\n",
  878. X            line[1], *escape, *escape);
  879. X    }
  880. X    (void) fseek(ed_fp, 0L, 2); /* seek to end of file in case there's more */
  881. X    wprint("(continue editing letter)\n");
  882. X    return 1;
  883. X}
  884. X
  885. X/*
  886. X * finish up the letter. ask for the cc line, if verify is set, ask to
  887. X * verify sending, continue editing, or to dump the whole idea.
  888. X * Then check for signature and fortune.  Finally, pass it to send_it()
  889. X * to actually send it off.
  890. X */
  891. finish_up_letter()
  892. X{
  893. X    register char *p;
  894. X    int c;
  895. X    char buf[MAXPATHLEN];
  896. X
  897. X    /* forwarded mail has no additional peronalized text */
  898. X    if (ison(flags, FORWARD)) {
  899. X    send_it();
  900. X    turnoff(glob_flags, IS_GETTING);
  901. X    return 1;
  902. X    }
  903. X
  904. X    if (isoff(glob_flags, REDIRECT)) {
  905. X    if (!istool &&
  906. X        do_set(set_options, "askcc") && (p = set_header("Cc: ", Cc, 1)))
  907. X        (void) strcpy(Cc, p);
  908. X    /* ~v on the Cc line asks for verification, first initialize p! */
  909. X    p = NULL;
  910. X    if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  911. X        if (!p) /* so we don't Cc to ~v! */
  912. X        *Cc = 0;
  913. X        for (;;) {
  914. X#ifdef SUNTOOL
  915. X        if (istool) {
  916. X            type_cursor(PIX_CLR);
  917. X            print("Send, Continue, Discard [Left, Middle, Right]?");
  918. X            c = confirm(msg_sw->ts_windowfd);
  919. X            clr_bot_line(); /* really: clears print window */
  920. X            if (isascii(c))
  921. X            Lower(c);
  922. X            else switch(c) {
  923. X            when MS_LEFT : c = 's';
  924. X            when MS_MIDDLE : c = 'c';
  925. X            when MS_RIGHT : c = 'd';
  926. X            otherwise: c = 0;
  927. X            }
  928. X        } else
  929. X#endif /* SUNTOOL */
  930. X        {
  931. X            print("send, continue editing, discard [s,c,d]? ");
  932. X            c = Getstr(buf, sizeof(buf), 0);
  933. X        }
  934. X        if (c < 0)
  935. X            putchar('\n');
  936. X        else if (!istool)
  937. X            c = lower(*buf);
  938. X        if (c == 'd') {
  939. X            rm_edfile(-2);
  940. X            return 1;
  941. X        } else if (c == 'c') {
  942. X            wprint("(continue editing letter)\n");
  943. X#ifdef SUNTOOL
  944. X            if (istool)
  945. X            type_cursor(PIX_SRC);
  946. X#endif /* SUNTOOL */
  947. X            return 0;
  948. X        } else if (c == 's')
  949. X            break;
  950. X        }
  951. X    }
  952. X    }
  953. X
  954. X#ifdef SUNTOOL
  955. X    if (istool)
  956. X    lock_cursors();
  957. X#endif /* SUNTOOL */
  958. X    send_it();
  959. X    turnoff(glob_flags, IS_GETTING);
  960. X    return 1;
  961. X}
  962. X
  963. X/*
  964. X * actually send the letter.
  965. X * 1. reset all the signals because of fork.
  966. X * 2. determine recipients (users, address, files, programs)
  967. X * 3. determine mailer, fork and return (if not verbose).
  968. X * 4. popen mailer, $record, and other files specified in step 1.
  969. X * 5. make the headers; this includes To: line, and user set headers, etc...
  970. X * 6. copy the letter right into the array of file pointers (step 1).
  971. X * 7. close the mailer and other files (step 1) and remove the edit-file.
  972. X */
  973. static void
  974. send_it()
  975. X{
  976. X    register char *p, *b, *addr_list;
  977. X#ifdef MAXFILES
  978. X    register int size = MAXFILES - 1;
  979. X    FILE *files[MAXFILES];
  980. X#else
  981. X    register int size = getdtablesize() - 1;
  982. X    FILE *files[30];  /* 30 should be sufficiently large enough */
  983. X#endif /* MAXFILES */
  984. X    int next_file = 1; /* reserve files[0] for the mail delivery program */
  985. X    char buf[3*BUFSIZ];
  986. X    char expand = !do_set(set_options, "no_expand");
  987. X
  988. X    if (!istool) {
  989. X    (void) signal(SIGINT, oldint);
  990. X    (void) signal(SIGQUIT, oldquit);
  991. X    (void) signal(SIGTERM, oldterm);
  992. X    }
  993. X
  994. X    if (!(p = do_set(set_options, "sendmail")))
  995. X    p = MAIL_DELIVERY;
  996. X
  997. X#ifdef VERBOSE_ARG
  998. X    if (ison(flags, VERBOSE) || do_set(set_options, "verbose"))
  999. X    b = &buf[strlen(sprintf(buf, "%s %s", p, VERBOSE_ARG))];
  1000. X    else
  1001. X#endif /* VERBOSE_ARG */
  1002. X    b = buf + Strcpy(buf, p);
  1003. X#ifdef METOO_ARG
  1004. X    if (!strcmp(p, MAIL_DELIVERY) && do_set(set_options, "metoo"))
  1005. X    b += strlen(sprintf(b, " %s", METOO_ARG));
  1006. X#endif /* METOO_ARG */
  1007. X    *b++ = ' ', *b = 0; /* strcat(b, " "); */
  1008. X    addr_list = b; /* save this position to check for addresses later */
  1009. X
  1010. X    /*
  1011. X     * Build the address lines to give to the mail transfer system.  This
  1012. X     * address line connot contain comment fields!  First, expand aliases
  1013. X     * since they may contain comment fields within addresses. Copy this
  1014. X     * result back into the Buffer since this will go into the header ...
  1015. X     * Next, remove all comments so the buffer contains ONLY valid addresses.
  1016. X     * Next, strip off any filenames/programs which might occur in the list.
  1017. X     * Finally, add this information to the command line buffer (buf).
  1018. X     * Remove commas if necessary (see ifdef's).  In the event of errors,
  1019. X     * force a dead letter by rm_edfile(-1). But, rm_edfile will exit with -1
  1020. X     * arg, so kludge by turning on the VERBOSE bit in "flags".
  1021. X     */
  1022. X    if (!(p = alias_to_address(To))) {
  1023. X    print("address expansion failed for To: line.\n");
  1024. X    turnon(flags, VERBOSE);
  1025. X    rm_edfile(-1);
  1026. X    } else {
  1027. X    next_file += find_files(p, files+next_file, size - next_file);
  1028. X    if (expand)
  1029. X        (void) strcpy(To, p);
  1030. X    rm_cmts_in_addr(p);
  1031. X    skipspaces(0);
  1032. X    if (!*p) {
  1033. X        print("There must be at least 1 legal recipient on the To line\n");
  1034. X        while (--next_file > 1)
  1035. X        fclose(files[next_file]);
  1036. X        rm_edfile(-2);
  1037. X        return;
  1038. X    }
  1039. X    b += Strcpy(b, p);
  1040. X    }
  1041. X    if (*Cc) {
  1042. X    if (!(p = alias_to_address(Cc))) {
  1043. X        print("address expansion failed for Cc: line.\n");
  1044. X        turnon(flags, VERBOSE);
  1045. X        while (--next_file > 1)
  1046. X        fclose(files[next_file]);
  1047. X        rm_edfile(-1);
  1048. X    } else {
  1049. X        next_file += find_files(p, files+next_file, size - next_file);
  1050. X        if (expand)
  1051. X        (void) strcpy(Cc, p);
  1052. X        rm_cmts_in_addr(p);
  1053. X        skipspaces(0);
  1054. X        if (*p) {
  1055. X        *b++ = ',', *b++ = ' ';
  1056. X        b += Strcpy(b, p);
  1057. X        }
  1058. X    }
  1059. X    }
  1060. X
  1061. X    /* Sign the letter before adding the Bcc list since they aren't
  1062. X     * considered when adding a signature.
  1063. X     */
  1064. X    if (ison(flags, SIGN) && isoff(glob_flags, REDIRECT))
  1065. X    sign_letter(addr_list);
  1066. X
  1067. X    if (*Bcc) {
  1068. X    if (!(p = alias_to_address(Bcc))) {
  1069. X        print("address expansion failed for Bcc: line.\n");
  1070. X        turnon(flags, VERBOSE);
  1071. X        while (--next_file > 1)
  1072. X        fclose(files[next_file]);
  1073. X        rm_edfile(-1);
  1074. X    } else {
  1075. X        next_file += find_files(p, files+next_file, size - next_file);
  1076. X        (void) strcpy(Bcc, p);
  1077. X        rm_cmts_in_addr(p);
  1078. X        skipspaces(0);
  1079. X        if (*p) {
  1080. X        *b++ = ',', *b++ = ' ';
  1081. X        b += Strcpy(b, p);
  1082. X        }
  1083. X    }
  1084. X    }
  1085. X
  1086. X#ifdef OLD_MAILER
  1087. X    for (p = buf; p = index(p, ','); p++)
  1088. X    *p = ' ';
  1089. X#endif /* OLD_MAILER */
  1090. X
  1091. X    Debug("mail command: %s\n", buf);
  1092. X
  1093. X#ifdef SUNTOOL
  1094. X    if (istool)
  1095. X    abort_mail(NO_ITEM, 0);
  1096. X#endif /* SUNTOOL */
  1097. X
  1098. X    if (isoff(flags, VERBOSE) && debug < 3)
  1099. X    switch (fork()) {
  1100. X        case  0:  /* the child will send the letter. ignore signals */
  1101. X#ifdef SYSV
  1102. X        if (setpgrp() == -1)
  1103. X            error("setpgrp");
  1104. X#endif /* SYSV */
  1105. X        (void) signal(SIGINT, SIG_IGN);
  1106. X        (void) signal(SIGHUP, SIG_IGN);
  1107. X        (void) signal(SIGQUIT, SIG_IGN);
  1108. X        (void) signal(SIGTERM, SIG_IGN);
  1109. X#ifdef SIGTTIN
  1110. X        (void) signal(SIGTTOU, SIG_IGN);
  1111. X        (void) signal(SIGTTIN, SIG_IGN);
  1112. X#endif /* SIGTTIN */
  1113. X#ifdef SIGCONT
  1114. X        (void) signal(SIGCONT, SIG_IGN);
  1115. X        (void) signal(SIGTSTP, SIG_IGN);
  1116. X#endif /* SIGCONT */
  1117. X        turnon(glob_flags, IGN_SIGS);
  1118. X        break;
  1119. X        case -1:
  1120. X        error("fork failed trying to send mail");
  1121. X        default:
  1122. X        if (isoff(glob_flags, REDIRECT))
  1123. X            fclose(ed_fp);
  1124. X#ifdef SUNTOOL
  1125. X                if (istool) {
  1126. X            wprint("Letter sent.");
  1127. X            print("Letter sent.");
  1128. X            type_cursor(PIX_CLR);
  1129. X        }
  1130. X#endif /* SUNTOOL */
  1131. X        while (--next_file > 0)
  1132. X            fclose(files[next_file]);
  1133. X        return;
  1134. X    }
  1135. X
  1136. X    if (debug > 2)
  1137. X    files[0] = stdout;
  1138. X    else if (!(files[0] = open_file(buf, TRUE))) {
  1139. X    rm_edfile(-1); /* force saving of undeliverable mail */
  1140. X    return;
  1141. X    }
  1142. X
  1143. X    if (ison(flags, VERBOSE))
  1144. X    wprint("Sending letter ... ");
  1145. X
  1146. X    /* see if record is set.  If so, open that file for appending and add
  1147. X     * the letter in a format such that mail can be read from it
  1148. X     */
  1149. X    if (p = do_set(set_options, "record")) {
  1150. X    if (!*p)
  1151. X        p = "~/record";
  1152. X    (void) strcpy(buf, p);
  1153. X    next_file += find_files(buf, files+next_file, size - next_file);
  1154. X    }
  1155. X
  1156. X    /* Make folders conform to RFC-822 by adding From: and Date: headers.
  1157. X     * Some older mailers (binmail, execmail, delivermail), don't add
  1158. X     * these headers to the MTA, so add them for OLD_MAIL systems.
  1159. X     */
  1160. X    for (size = 0; size < next_file; size++) {
  1161. X    time_t t;
  1162. X#ifndef OLD_MAIL
  1163. X    if (size == 0)
  1164. X        continue;
  1165. X#endif /* OLD_MAIL */
  1166. X    (void) time(&t);
  1167. X    if (size > 0) {
  1168. X#ifndef MSG_SEPARATOR
  1169. X        fprintf(files[size], "From %s %s", login, ctime(&t));
  1170. X#else /* MSG_SEPARATOR */
  1171. X        fprintf(files[size], "%s\n", MSG_SEPARATOR);
  1172. X#endif /* MSG_SEPARATOR */
  1173. X    }
  1174. X    fprintf(files[size], "From: %s\n", login);
  1175. X    fprintf(files[size], "Date: %s", ctime(&t));
  1176. X    }
  1177. X
  1178. X    /* first print users own message headers */
  1179. X    if (own_hdrs && !do_set(set_options, "no_hdrs")) {
  1180. X    struct options *opts;
  1181. X    for (opts = own_hdrs; opts; opts = opts->next)
  1182. X        for (size = 0; size < next_file; size++)
  1183. X        fprintf(files[size], "%s %s\n", opts->option, opts->value);
  1184. X    }
  1185. X
  1186. X    /* send the header stuff to sendmail and end header with a blank line */
  1187. X    for (size = 0; size < next_file; size++) {
  1188. X    if (*in_reply_to)
  1189. X        fprintf(files[size], "In-Reply-To: %s\n", in_reply_to);
  1190. X    fprintf(files[size], "X-Mailer: %s\n", VERSION);
  1191. X    fprintf(files[size], "%sTo: %s\n",
  1192. X        ison(flags, FORWARD) ? "Resent-" : "", To);
  1193. X    if (*Subject)
  1194. X        fprintf(files[size], "Subject: %s\n", Subject);
  1195. X    if (*Cc)
  1196. X        fprintf(files[size], "%sCc: %s\n",
  1197. X        ison(flags, FORWARD) ? "Resent-" : "", Cc);
  1198. X    if (size > 0) {
  1199. X        /* Do not send these to mail transfer agent */
  1200. X        if (*Bcc)
  1201. X        fprintf(files[size], "Bcc: %s\n", Bcc);
  1202. X        fprintf(files[size], "Status: OR\n");
  1203. X    }
  1204. X    fputc('\n', files[size]);
  1205. X    }
  1206. X
  1207. X    /* if redirection, ed_fp = stdin, else rewind the file just made */
  1208. X    if (isoff(glob_flags, REDIRECT))
  1209. X    rewind(ed_fp);
  1210. X    else
  1211. X    ed_fp = stdin;
  1212. X
  1213. X    /* read from stdin or the edfile till EOF and send it all to the mailer
  1214. X     * and other open files/folders/programs. Check for "From " at the
  1215. X     * beginnings of these lines to prevent creating new messages in folders.
  1216. X     */
  1217. X    while (fgets(buf, BUFSIZ, ed_fp))
  1218. X    for (size = 0; size < next_file; size++) {
  1219. X        if (!strncmp(buf, "From ", 5))
  1220. X        fputc('>', files[size]);
  1221. X        fputs(buf, files[size]);
  1222. X    }
  1223. X
  1224. X    /* loop thru the open files (except for the first: the mail delivery agent)
  1225. X     * and append a blank line so that ucb-mail can read these folders.
  1226. X     * Then close the files.  If the file was a popened program, the sigchld
  1227. X     * that the program generates will close the file.
  1228. X     */
  1229. X    for (size = 1; size < next_file; size++)
  1230. X    if (files[size]) {
  1231. X        fputc('\n', files[size]);
  1232. X        fclose(files[size]);
  1233. X    }
  1234. X
  1235. X    rm_edfile(0);
  1236. X    if (debug < 3)
  1237. X    (void) pclose(files[0]);
  1238. X
  1239. X    if ((ison(flags, VERBOSE) || debug > 2) && isoff(glob_flags, REDIRECT))
  1240. X    wprint("sent.\n");
  1241. X    else
  1242. X    exit(0); /* not a user exit -- a child exit */
  1243. X}
  1244. X
  1245. X/* ARGSUSED */
  1246. rm_edfile(sig)
  1247. X{
  1248. X    if (sig > 0 && !killme) {
  1249. X    if (!istool)
  1250. X        (void) signal(sig, rm_edfile);
  1251. X    killme = 1;
  1252. X    wprint("\n** interrupt -- one more to kill letter **\n");
  1253. X#ifdef SUNTOOL
  1254. X    if (istool) {
  1255. X        type_cursor(PIX_SRC);
  1256. X        return;
  1257. X    }
  1258. X#endif /* SUNTOOL */
  1259. X    longjmp(cntrl_c_buf, 1);
  1260. X    }
  1261. X    killme = 0;
  1262. X    /* if sig == -1, force a save into dead.letter.
  1263. X     * else, check for nosave not being set and save anyway if it's not set
  1264. X     * sig == 0 indicates normal exit (or ~x), so don't save a dead letter.
  1265. X     */
  1266. X    if (sig == -1 || sig != 0 && !do_set(set_options, "nosave"))
  1267. X    dead_letter();
  1268. X    if (isoff(glob_flags, REDIRECT))
  1269. X    fclose(ed_fp);
  1270. X    (void) unlink(edfile);
  1271. X
  1272. X    if (sig == -1 && isoff(flags, VERBOSE) && debug < 3)
  1273. X    exit(-1);
  1274. X
  1275. X    turnoff(glob_flags, IS_GETTING);
  1276. X#ifdef SUNTOOL
  1277. X    if (sig && istool > 1) {
  1278. X    wprint("*Letter aborted*");
  1279. X    abort_mail(abort_item, 2);
  1280. X    }
  1281. X#endif /* SUNTOOL */
  1282. X
  1283. X    if (sig == SIGHUP)
  1284. X    cleanup(0);
  1285. X    if (!istool) {
  1286. X    (void) signal(SIGINT, oldint);
  1287. X    (void) signal(SIGQUIT, oldquit);
  1288. X    (void) signal(SIGTERM, oldterm);
  1289. X    }
  1290. X
  1291. X    if (sig == 0)
  1292. X    return;
  1293. X    if (istool || sig == -2) /* make sure sigchld is reset first */
  1294. X    return;
  1295. X
  1296. X    if (isoff(glob_flags, DO_SHELL)) {  /* If we're not in a shell, exit */
  1297. X    puts("exiting");
  1298. X    echo_on();
  1299. X    exit(1);
  1300. X    }
  1301. X    longjmp(jmpbuf, 1);
  1302. X}
  1303. X
  1304. X/* save letter into dead letter */
  1305. dead_letter()
  1306. X{
  1307. X    char     *p, buf[BUFSIZ];
  1308. X    long     t;
  1309. X    FILE     *dead;
  1310. X
  1311. X    if (ison(glob_flags, REDIRECT)) {
  1312. X    print("input redirected -- can't save dead letter.\n");
  1313. X    return;
  1314. X    }
  1315. X    /* If the file doesn't exist, get outta here. File may not exist if
  1316. X     * user generated a ^C from a promptable header and catch sent us here.
  1317. X     */
  1318. X    if (Access(edfile, R_OK))
  1319. X    return;
  1320. X    /* User may have killed mush via a signal while he was in an editor.
  1321. X     * ed_fp will be NULL in this case.  Since the file does exist (above),
  1322. X     * open it so we can copy it to dead letter.
  1323. X     */
  1324. X    if (!ed_fp && !(ed_fp = fopen(edfile, "r"))) {
  1325. X    error("can't save dead letter from %s", edfile);
  1326. X    return;
  1327. X    }
  1328. X    /* don't save a dead letter if there's nothing to save. */
  1329. X    if (fseek(ed_fp, 0L, 2) || ftell(ed_fp) == 0L)
  1330. X    return;
  1331. X    if (!(p = do_set(set_options, "dead")))
  1332. X    p = "~/dead.letter";
  1333. X    if (!(dead = open_file(p, FALSE)))
  1334. X    return;
  1335. X    (void) time (&t);
  1336. X    fflush(ed_fp);
  1337. X    rewind(ed_fp);
  1338. X    fprintf(dead, "Unfinished letter from %s", ctime(&t));
  1339. X    fprintf(dead, "To: %s\nSubject: %s\n", To, Subject);
  1340. X    if (*Cc)
  1341. X    fprintf(dead, "Cc: %s\n", Cc);
  1342. X    while(fgets(buf, sizeof(buf), ed_fp))
  1343. X    (void) fputs(buf, dead);
  1344. X    (void) fputc('\n', dead);
  1345. X    (void) fclose(dead);
  1346. X    print("Saved unfinished letter in %s.\n", p);
  1347. X}
  1348. X
  1349. X/*
  1350. X * Your "signature" is of the type:
  1351. X *    file_or_path
  1352. X *    $varaible
  1353. X *    \ literal string preceded by a backslash.
  1354. X * The variable will be expanded into its string value.
  1355. X * To sign the letter, the list of addresses is passed to this routine
  1356. X * (separated by spaces and/or commas).  If "autosign2" is set,
  1357. X * then it must be of the form.
  1358. X * autosign2 = "user@foo user@bar address...: <signature>"
  1359. X * Spaces or tabs separate tokens.  If everyone on the list exists in
  1360. X * the autosign2 list, the alternate signature is used. In case of
  1361. X * syntax error, the alternate signature is used without checks (e.g. if
  1362. X * the : is missing).  The alternate signature == null is the same as
  1363. X * not signing the letter. An empty list forces signature2.
  1364. X *
  1365. X * If autosign2 is not set at all, then autosign is checked and used.
  1366. X * autosign = <signature>
  1367. X */
  1368. sign_letter(list)
  1369. register char *list; /* list of addresses -- no comment fields */
  1370. X{
  1371. X    char buf[BUFSIZ];
  1372. X    register char *p, *p2, *signature, *addr;
  1373. X    FILE     *pp2;
  1374. X    int     lines = 0;
  1375. X
  1376. X    buf[0] = 0;
  1377. X    while (isspace(*list))
  1378. X    list++;
  1379. X    if (p = do_set(set_options, "autosign2")) {
  1380. X    if (!(signature = index(p, ':')))
  1381. X        wprint("\"autosign2\" incorrectly set (missing `:').\n");
  1382. X    else {
  1383. X        int ret_val = 0;
  1384. X        *signature = 0;
  1385. X        /* p now points to a list of addresses and p2 points to the
  1386. X         * signature format to use. Check that each address contains
  1387. X         * the stuff in alternate sign.
  1388. X         */
  1389. X        skipspaces(0);
  1390. X        if (!*p)
  1391. X        /* autosign2 = " : <signature>"  send to all recipients */
  1392. X        ret_val = 1;
  1393. X        else if (p = alias_to_address(p)) {
  1394. X        rm_cmts_in_addr(p);
  1395. X        for (addr = list;;) {
  1396. X            char c;
  1397. X            if (p2 = any(addr, ", ")) {
  1398. X            c = *p2;
  1399. X            *p2 = 0;
  1400. X            }
  1401. X            ret_val = chk_two_lists(addr, p, ", ");
  1402. X            if (p2)
  1403. X            for (*p2++ = c; isspace(*p2) || *p2 == ','; p2++)
  1404. X                ;
  1405. X            if (!ret_val || !(addr = p2))
  1406. X            break;
  1407. X        }
  1408. X        }
  1409. X        *signature++ = ':'; /* must reset first! */
  1410. X        if (ret_val) {
  1411. X        while (isspace(*signature))
  1412. X            signature++;
  1413. X        if (!*strcpy(buf, signature))
  1414. X            return;
  1415. X        }
  1416. X    }
  1417. X    }
  1418. X    if (!buf[0]) {
  1419. X    if (!(p = do_set(set_options, "autosign")) || !*p) {
  1420. X        char *home;
  1421. X        if (!(home = do_set(set_options, "home")) || !*home)
  1422. X        home = ALTERNATE_HOME;
  1423. X        (void) sprintf(buf, "%s/%s", home, SIGNATURE);
  1424. X    } else
  1425. X        (void) strcpy(buf, p);
  1426. X    wprint("Signing letter... ");
  1427. X    } else
  1428. X    wprint("Using alternate signature... ");
  1429. X    fputc('\n', ed_fp), fflush(ed_fp);
  1430. X    (void) fseek(ed_fp, 0L, 2); /* guarantee position at end of file */
  1431. X    if (*buf == '$')
  1432. X    if (!(p = do_set(set_options, buf)))
  1433. X        wprint("(%s isn't set -- letter not signed)\n", buf);
  1434. X    else
  1435. X        fprintf(ed_fp, "%s\n", p), wprint("\n"), fflush(ed_fp);
  1436. X    else if (*buf == '\\')
  1437. X    fprintf(ed_fp, "%s\n", buf+1), wprint("\n"), fflush(ed_fp);
  1438. X    else
  1439. X    file_to_fp(buf, ed_fp, "r");
  1440. X
  1441. X    /* if fortune is set, check to see if fortunates is set. If so,
  1442. X     * check to see if all the recipient are on the fortunates list.
  1443. X     */
  1444. X    if (ison(flags, DO_FORTUNE)) {
  1445. X    if (p = do_set(set_options, "fortunates")) {
  1446. X        int ret_val;
  1447. X        if (!(p = alias_to_address(p)))
  1448. X        return; /* no reason to hang around */
  1449. X        rm_cmts_in_addr(p);
  1450. X        for (addr = list;;) {
  1451. X        char c;
  1452. X        if (p2 = any(addr, ", ")) {
  1453. X            c = *p2;
  1454. X            *p2 = 0;
  1455. X        }
  1456. X        if (!(ret_val = chk_two_lists(addr, p, ", ")))
  1457. X            (void) strcpy(buf, addr);
  1458. X        if (p2)
  1459. X            for (*p2++ = c; isspace(*p2) || *p2 == ','; p2++)
  1460. X            ;
  1461. X        if (!ret_val || !(addr = p2))
  1462. X            break;
  1463. X        }
  1464. X        if (!ret_val) {
  1465. X        wprint("\"fortunates\" does not contain \"%s\".\n", buf);
  1466. X        wprint("No fortune added.\n");
  1467. X        return;
  1468. X        }
  1469. X    }
  1470. X    wprint("You may be fortunate... ");
  1471. X    if ((p = do_set(set_options, "fortune")) && *p == '/')
  1472. X        (void) strcpy(buf, p);
  1473. X    else
  1474. X        (void) sprintf(buf, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
  1475. X    if (!(pp2 = popen(buf, "r")))
  1476. X        error(buf);
  1477. X    else {
  1478. X        turnon(glob_flags, IGN_SIGS);
  1479. X        (void) fseek(ed_fp, 0L, 2); /* go to end of file */
  1480. X        while (fgets(buf, sizeof(buf), pp2))
  1481. X        fputs(buf, ed_fp), lines++;
  1482. X        (void) pclose(pp2);
  1483. X        turnoff(glob_flags, IGN_SIGS);
  1484. X        fflush(ed_fp);
  1485. X        wprint("added %d line%s\n", lines, lines == 1? "" : "s");
  1486. X    }
  1487. X    }
  1488. X}
  1489. END_OF_FILE
  1490. if test 44050 -ne `wc -c <'mail.c'`; then
  1491.     echo shar: \"'mail.c'\" unpacked with wrong size!
  1492. fi
  1493. # end of 'mail.c'
  1494. fi
  1495. echo shar: End of archive 14 \(of 14\).
  1496. cp /dev/null ark14isdone
  1497. MISSING=""
  1498. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  1499.     if test ! -f ark${I}isdone ; then
  1500.     MISSING="${MISSING} ${I}"
  1501.     fi
  1502. done
  1503. if test "${MISSING}" = "" ; then
  1504.     echo You have unpacked all 14 archives.
  1505.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1506. else
  1507.     echo You still need to unpack the following archives:
  1508.     echo "        " ${MISSING}
  1509. fi
  1510. ##  End of shell archive.
  1511. exit 0
  1512.